//
// Created by yuhaibo on 18-11-16.
//

//#ifndef ANDROID_OTA_H
//#define ANDROID_OTA_H
#ifndef VENDOR_ECARX_OTA_V2_0_OTA_H
#define VENDOR_ECARX_OTA_V2_0_OTA_H

#include <android-base/properties.h>
#include "WorkerThread.h"
#include <ipcp/ipcp.h>
#include <log/log.h>
#include <vendor/ecarx/xma/ota/2.0/IOta.h>
#include <vendor/ecarx/xma/ota/2.0/IOtaClientCallback.h>
#include <vendor/ecarx/xma/ota/2.0/types.h>
#include <chrono>
#include <thread>
#include <optional>
#include <functional>

namespace vendor {
namespace ecarx {
namespace xma {
namespace ota {
namespace V2_0 {

using std::lock_guard;
using std::mutex;
using std::chrono::milliseconds;
using std::chrono_literals::operator""ms;
using ::android::sp;
using ::android::wp;
using ::android::hardware::hidl_death_recipient;
using ::android::hardware::hidl_string;
using ::android::hardware::Return;
using ::android::hardware::Void;

#define OTA_IPCP_VERSION 13
//-----------------------------------------------------------
// for ota_test
// local
#define TEST_LOCAL_IP "127.0.0.1"
#define TEST_LOCAL_PORT 8888
#define TEST_VLAN_ID 0
#define TEST_VLAN_PRIORITY 0
// remote
#define TEST_SERVICE_IP "127.0.0.1"
#define TEST_SERVICE_PORT 6666
#define TEST_MODE 1
//-----------------------------------------------------------
// for OTA
#define LOCAL_IP "198.18.34.15"
#define LOCAL_PORT 50193

#define PEER_IP "198.18.32.17"
#define PEER_PORT 50193

#define PEER_VGM_IP "198.18.32.1"
#define PEER_VGM_PORT 50193

#define PEER_ADCU_IP "198.18.36.3"
#define PEER_ADCU_PORT 50193
#define DIAGNOSE_ADDR_ADCU "1301"

#define PEER_FLC_IP "198.18.35.161"
#define PEER_FLC_PORT 50193
#define DIAGNOSE_ADDR_FLC "13A1"

#define SERVICE_ID 0xC1
#define VLAN 2
#define PRIORITY 0
#define OTA_MODE 0
//------------------------------------------------------------

#define OP_TYPE_REQUEST 0x00
#define OP_TYPE_RESPONSE 0x04
#define OP_TYPE_NOTIFICATION 0x05
#define OP_TYPE_ERROR 0xE0

// Define Service ID
#define SERVICE_ID_OTA 0xC1

// Define Operation Type
#define OP_ID_DOWNLOAD_CONSENT 0x0B19
#define OP_ID_INSTALLATION_CONSENT 0x0B20
#define OP_ID_USER_OTA_SETTINGS 0x0B21
#define OP_ID_OTA_ASSIGNMENT_SYNC 0x0B22
#define OP_ID_OTA_DHU_ASSIGNMENT_NOTIFICATION 0x0B24
#define OP_ID_OTA_DOWNLOAD_PROGRESS 0x0B25
#define OP_ID_OTA_HMI_ETTINGS 0x0B51
#define OP_ID_CONNECTIVITY_STATUS 0x0B52
#define OP_ID_APP_INSTALL_CONSENT 0x0B56
#define OP_ID_SYNC_SCH_INSTALL_TIME 0x0BA3
#define OP_ID_OTA_INSTALLATION_REGRET_TIMEOUT 0x0B59
#define OP_ID_BSSID_DISPLAYEDVERSION_SYNC 0x0B60

#define OP_ID_OTA_DOWNLOAD_STATUS 0x0B61
#define OP_ID_OTA_ASSIGNMENT_KEY_TO_TARGET_ECU 0x0B62 
#define OP_ID_OTA_URL_INFO 0x0B64

#define OP_ID_OTA_SIGNATURE_CERTIFICATE 0x0B55
#define OP_ID_OTA_EXCEPTION_REPORTS 0x0B28
#define OP_ID_OTA_WRITE_INSTALLATION_INSTRUCTION 0x0B16
#define OP_ID_OTA_SET_ASSIGNMENT_FILE_INFO 0x0B29
#define OP_ID_OTA_POST_INSTALLATION 0x0B72
#define OP_ID_OTA_SET_SCHEDULE_TIME 0x0BA2
#define OP_ID_NEW_USER_APP_SETTINGS 0x0BA5
#define OP_ID_PRE_SALE_INFO 0x0BA4

#define OP_ID_OTA_NOTIFICATION_TO_MASTER_CHANGE 0x0BA1

#define OP_ID_RVDC_LOG_TRANSFER_RETRY 0x0BE0
#define OP_ID_RVDC_TRANSFER_LOGS_CRC 0x0BE1
#define OP_ID_RVDC_VERIFICATION_CRC_STATUS 0x0BE2
#define OP_ID_RVDC_TRANSFER_LOGS_DATA 0x0BE3

#define OTA_SETTING "persist.ota.setting"
#define OTA_AUTO_SYNC "persist.ota.auto.sync"
#define OTA_AUTO_DOWNLOAD "persist.ota.auto.download"
#define OTA_AUTO_INSTALL "persist.ota.auto.install"

#define ASN_HEADER_LENGTH_OFFSET 8

typedef void (*ota_callback)(int status);


class Ota : public IOta {
  public:
    Ota();

    ~Ota();

    virtual void onFirstRef();

    Return<StatusCode> init_ota_ipcp() override;

    Return<StatusCode> init_ota_ipcp_test();

    Return<StatusCode> subscribe(const ::android::sp<IOtaClientCallback>& callback) override;

    Return<StatusCode> unsubscribe(const ::android::sp<IOtaClientCallback>& callback) override;

    Return<StatusCode> requestOTAConnectivitySts() override;
    Return<StatusCode> notificationToMasterChangeRsp(const hidl_string& status) override;

    Return<StatusCode> startDistributeEcuDownload(const StartDownloadRequestHal& startDownloadRequestHal) override;

    Return<StatusCode> pauseDistributeEcuDownload(const OpOTAECUAssignmentStatusHal& opOTAECUAssignmentStatusHal) override;

    Return<StatusCode> resumeDistributeEcuDownload(const OpOTAECUAssignmentStatusHal& opOTAECUAssignmentStatusHal) override;

    Return<StatusCode> terminateDistributeEcuDownload(const OpOTAECUAssignmentStatusHal& opOTAECUAssignmentStatusHal) override;

    Return<StatusCode> scheduleTime(const hidl_string& installationOrder, InstallationConsent installationConsent, int32_t deltatime) override;

    Return<int32_t> requestSchInstallTime(int32_t timeout) override;

    Return<StatusCode> setTcamSalesMode(SaleMode type, int32_t timeout) override;

    int bytesToInt(u_int8_t* bytes);

    static sp<Ota> getOta(void* cookie);

    sp<IOtaClientCallback> getCallback();

    void handleHidlDeath();


  private:
    class DeathRecipient : public hidl_death_recipient {
      public:
        DeathRecipient(sp<Ota> ota) : mOta(ota) {}
        ~DeathRecipient() = default;
        virtual void serviceDied(uint64_t cookie /*cookie*/,
                                 const wp<android::hidl::base::V1_0::IBase>& /*who*/) {
            ALOGD("function: %s, service %lu", __func__, cookie);
            mOta->handleHidlDeath();
        }

      private:
        sp<Ota> mOta;
    };

    void sendDHUAssignmentNotification(const char* ecuaddress, const char* uuid, const char* timestamp, const char* newstatus, const char* reason);
    void sendWriteInstallInstructionSync();
    void sendWriteInstallInstructionRequest();
    void sendAssignmentFileInfoSync();
    void sendAssignmentFileInfoRequest();
    void sendSignatureCertificateSync();
    void sendSignatureCertificateRequest();
    void sendUrlInfoSync();
    void sendUrlInfoRequest();
    Return<void> debug(const android::hardware::hidl_handle& handle, const android::hardware::hidl_vec<hidl_string>& options);
    //-------------------------- ota test --------------------------
  private:
    mutex mMut;
    sp<IOtaClientCallback> mCallback;
    WorkerThread mThread;

    static ota_callback gOtaCallback;
    sp<DeathRecipient> mCallbackDeathRecipient;
    StartDownloadRequestHal mRequest;

};

// } // namespace implementation
}  // namespace V2_0
}  // namespace ota
}  // namespace xma
}  // namespace ecarx
}  // namespace vendor
#endif  // VENDOR_ECARX_OTA_V2_0_OTA_H
